package com.gxlu.ms.web.filter;

import java.io.IOException;
import java.text.MessageFormat;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.gxlu.ms.base.module.context.RpcContext;
import com.gxlu.ms.base.module.profile.JProfile;
import com.gxlu.ms.base.util.TraceUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author lhc
 * @date 2017年12月29日 下午5:14:20
 * Time打点Filter,记录方法执行的时间
 * 1.先用 JProfile.start("process HTTP request");
 *
 * 2.在方法执行前用：Profiler.enter("xxxx");
 * 3.方法执行最后或finally 中用Profiler.release()
 *
 * 4. JProfile.dump("Detail: ", "        ");
 * 5. JProfile.reset();
 */
@Order(1)
@Component("healthAdminFilter")
@WebFilter(filterName = "timeFilter", urlPatterns = "*",
    initParams = {@WebInitParam(name = "exclude_url", value = ".*/js/.*;.*.ico;.*.css;.*.js;/checkpreload.htm;/permission;/favicon")})
public class TimeFilter extends AbstractFilter {

    private int threshold;

    /**
     * 500 ms
     */
    private Integer processTimeOut = 500 ;

    @Override
    public void init() throws ServletException {
        String thresholdString = findInitParameter("threshold", processTimeOut.toString());
        if (thresholdString != null) {
            try {
                threshold = Integer.parseInt(thresholdString);
            } catch (NumberFormatException e) {
                threshold = processTimeOut.intValue();
            }
            if (threshold <= 0) {
                threshold = processTimeOut.intValue() ;
            }
        }
    }

    @Override
    public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
        throws IOException, ServletException {
        // 开始处理request, 并计时.
        String requestString = dumpRequest(request);

        if (log.isInfoEnabled() ) {
            log.info("Started processing request: " + requestString);
        }

        JProfile.start("process HTTP request");
        Throwable failed = null;
        try {
            //这里的 request 是Servlet 中的 request ,还没有被 shiro代理过，取完后，有问题，
            // long userId = SessionUtil.getCurrentUserId(request.getSession());
            //设置traceId
            TraceUtil.startTrace();
            TraceUtil.setStartTime(System.currentTimeMillis());
            /**
             * 是否压测,参数中带有 pt=1表示压测
             * 传0或其他值，都表示正常流量请求
             */
            String pt = request.getParameter("pt");
            if(StringUtils.isNotBlank(pt)){
                if(pt.equals("1")){
                    TraceUtil.putUserData(RpcContext.PERSIST_TEST,"1");
                }
            }
            TraceUtil.putUserData(RpcContext.PERSIST_TEST,"0");

            chain.doFilter(request, response);
        } catch (Throwable e) {
            failed = e;
        } finally {
            try{
                JProfile.release();
                long duration = JProfile.getDuration();
                if (failed != null) {
                    if (log.isErrorEnabled() ) {
                        log.error(MessageFormat.format("traceId={0},Response of {1} failed in {2,number}ms: {3}\n{4}\n", new Object[] {
                            TraceUtil.getTraceId(),requestString, new Long(duration), failed.getLocalizedMessage(), getDetail() }));
                    }
                } else if (duration > threshold) {
                    if (log.isWarnEnabled()) {
                        log.warn(MessageFormat.format("traceId={0},Response of {1} returned in {2,number}ms\n{3}\n", new Object[] {
                            TraceUtil.getTraceId(),requestString, new Long(duration), getDetail() }));
                    }
                }else {
                    if (log.isInfoEnabled() ) {
                        log.info(MessageFormat.format("traceId={0},Response of {1} returned in {2,number}ms\n{3}\n", new Object[] {
                            TraceUtil.getTraceId(),requestString, new Long(duration), getDetail() }));
                    }
                }
                JProfile.reset();
            }catch (Throwable e){
            }finally {
            }

            /**
             * 一定要清除，否则会有内存泄漏
             */
            TraceUtil.remove();
        }

        if (failed != null) {
            if (failed instanceof Error) {
                throw (Error) failed;
            } else if (failed instanceof RuntimeException) {
                throw (RuntimeException) failed;
            } else if (failed instanceof IOException) {
                throw (IOException) failed;
            } else if (failed instanceof ServletException) {
                throw (ServletException) failed;
            }
        }
    }

    private String getDetail() {
        return JProfile.dump("Detail: ", "        ");
    }

}
